home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Plus 1996 #1
/
Amiga Plus CD - 1996 - No. 1.iso
/
pd
/
netz
/
xbtx_v1.1
/
btxservice.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
1995-09-26
|
55KB
|
2,365 lines
/*
** $Id: BTXService.cpp 1.3 1995/09/26 16:48:58 olsen Exp olsen $
**
** :ts=4
*/
/*
* Amiga changes copyright © 1995 by Olaf Barthel, All Rights Reserved
*
* Copyright (c) 1992, 1993 Arno Augustin, Frank Hoering, University of
* Erlangen-Nuremberg, Germany.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* Erlangen-Nuremberg, Germany.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software has not been validated by the ``Bundesamt fuer Zulassungen in
* der Telekommunikation'' of the ``Deutsche Bundepost Telekom'' and thus
* must not be used for accessing the BTX-Network of the Telekom in Germany.
*
* Diese Software hat keine Zulassung durch das Bundesamt fuer Zulassungen in
* der Telekommunikation der Deutschen Bundespost Telekom und darf daher nicht
* am Netz der Deutschen Bundespost Telekom in Deutschland betrieben werden.
*/
#define USE_PROTOCOL
#include "BTXService.hpp"
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#define LOG(x) log()
#define ERRLOG(x) errlog()
/******************************************************************************/
BTXService::~BTXService()
{
Close();
}
BTXService::BTXService()
{
memset(screen,0,sizeof(screen));
memset(&t,0,sizeof(t));
memset(&backup,0,sizeof(backup));
memset(data,0,sizeof(data));
rows = fontheight = reachedEOF = 0;
pushback = -1;
telefile = NULL;
teledownload = FALSE;
telename[0] = 0;
telemode = MODE_Unknown;
#ifdef USE_PROTOCOL
protocolfile = NULL;
#endif
}
VOID BTXService::Close(VOID)
{
if(telefile)
{
fclose(telefile);
telefile = NULL;
}
#ifdef USE_PROTOCOL
if(protocolfile)
{
fclose(protocolfile);
protocolfile = NULL;
}
#endif
}
LONG BTXService::Open(BTXDisplay *Disp,Application *Appl)
{
AppDisplay = Disp;
App = Appl;
Disp->MonitorData(&rows,&fontheight);
#ifdef USE_PROTOCOL
protocolfile = fopen("t:protocol","wb");
#endif
init_layer6();
return(0);
}
int BTXService::ProcessInput(VOID)
{
return(process_BTX_data());
}
UBYTE BTXService::ConvertChar(int c,int s,int d)
{
static UBYTE supp_map[96] =
{ ' ', 0xa1, 0xa2, 0xa3, '$', 0xa5, '#', 0xa7, 0xa4, '`', '\"', 0xab,
0, 0, 0, 0, 0xb0, 0xb1, 0xb2, 0xb3, 0xd7, 0xb5, 0xb6, 0xb7, 0xf7,
'\'', '\"', 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0, 0x60, 0x27, 0, '~',
0xaf, 0, 0, 0x22, 0x22, 0xb0, 0, 0, 0x22, 0xb8, 0, 0xad, 0xb9, 0xae,
0xa9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xc6, 0, 0, 0, 0, 0,
0, 0, 0xd8, 0, 0, 0xfe, 0, 0, 0, 0, 0xe6, 0, 0, 0, 0, 0, 0, 0, 0xf8,
0, 0xdf, 0xde, 0, 0, 0 };
static UBYTE diacritical_map[26*2][16] = {
{ 0, 0xc0, 0xc1, 0xc2, 0xc3, 0, 0, 0, 0xc4, 0xc4, 0xc5, 0, 0, 0xc4, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* B */
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xc7, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* D */
{ 0, 0xc8, 0xc9, 0xca, 0, 0, 0, 0, 0xcb, 0xcb, 0, 0, 0, 0xcb, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* H */
{ 0, 0xcc, 0xcd, 0xce, 0, 0, 0, 0, 0xcf, 0xcf, 0, 0, 0, 0xcf, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0xd1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* N */
{ 0, 0xd2, 0xd3, 0xd4, 0xd5, 0, 0, 0, 0xd6, 0xd6, 0, 0, 0, 0xd6, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* T */
{ 0, 0xd9, 0xda, 0xdb, 0, 0, 0, 0, 0xdc, 0xdc, 0, 0, 0, 0xdc, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* X */
{ 0, 0, 0xdd, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0xe0, 0xe1, 0xe2, 0xe3, 0, 0, 0, 0xe4, 0xe4, 0xe5, 0, 0, 0xe4, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xe7, 0, 0, 0, 0 }, /* c */
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0xe8, 0xe9, 0xea, 0, 0, 0, 0, 0xeb, 0xeb, 0, 0, 0, 0xeb, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* h */
{ 0, 0xec, 0xed, 0xee, 0, 0, 0, 0, 0xef, 0xef, 0, 0, 0, 0xef, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0xf1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* n */
{ 0, 0xf2, 0xf3, 0xf4, 0xf5, 0, 0, 0, 0xf6, 0xf6, 0, 0, 0, 0xf6, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, /* t */
{ 0, 0xf9, 0xfa, 0xfb, 0, 0, 0, 0, 0xfc, 0xfc, 0, 0, 0, 0xfc, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0xfd, 0, 0, 0, 0, 0, 0xff, 0xff, 0, 0, 0, 0xff, 0, 0 }, /* y */
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } };
UBYTE Char;
/* ASCII out of 1st supplementary set of mosaic characters */
if(s==SUP1 && c>=0x40 && c<=0x5f)
Char = (UBYTE)c;
else
Char = (UBYTE)' ';
/* supplementary set of graphic characters */
if(s==SUPP && supp_map[c-0x20])
Char = (UBYTE)supp_map[c-0x20];
else
{
/* composed characters, diacritical marks (page 123) */
if(s==PRIM)
{
if(!d)
Char = (UBYTE)c; /* ASCII character */
else
{
if(d>=0x40 && d<=0x4f)
{
if(c>=0x41 && c<=0x5a && diacritical_map[c-0x41][d&0xf])
Char = (UBYTE)diacritical_map[c-0x41][d&0xf];
else
{
if(c>=0x61 && c<=0x7a && diacritical_map[c-0x61+26][d&0xf])
Char = (UBYTE)diacritical_map[c-0x61+26][d&0xf];
}
}
}
}
}
return(Char);
}
VOID BTXService::GetMatrix(UBYTE *Matrix,int *CursorX,int *CursorY)
{
if(Matrix)
{
int x,y;
memset(Matrix,' ',40 * 24);
for(y = 0 ; y < rows ; y++)
{
for(x = 0 ; x < 40 ; x++)
Matrix[y * 40 + x] = ConvertChar(screen[y][x].chr & 0x7f,screen[y][x].set,(screen[y][x].chr>>8) & 0x7f);
}
}
if(CursorX)
{
if(t.cursor_on)
*CursorX = t.cursorx;
else
*CursorX = -1;
}
if(CursorY)
{
if(t.cursor_on)
*CursorY = t.cursory;
else
*CursorY = -1;
}
}
/******************************************************************************/
/* all 'page' references refer to 'FTZ 157 D2 E' */
#include "Control.h"
#include "Font.h"
#include "Attributes.h"
/*
* initialize layer6 variables
*/
void BTXService::init_layer6()
{
int y;
fontheight = 10;
rows = 24;
t.cursorx = t.cursory = 1;
t.wrap = 1;
t.service_break = 0;
t.scroll_area = 0;
t.scroll_impl = 1;
t.cursor_on = 0;
t.par_attr = 0;
t.par_fg = WHITE;
t.par_bg = TRANSPARENT;
for(y=0; y<24; y++) AppDisplay->define_fullrow_bg(y, BLACK);
clearscreen();
default_sets();
}
/*
* Read and process one layer6 code sequence.
* Returns 1 when DCT (terminate data collect 0x1a) is received, else 0.
*/
int BTXService::process_BTX_data()
{
int set, c1, c2, dct=0;
c1 = layer2getc();
if(c1>=0x00 && c1<=0x1f)
dct = primary_control_C0(c1);
else
{
if(c1>=0x80 && c1<=0x9f)
supplementary_control_C1(c1, 0);
else
{
if(t.sshift)
set = t.G0123L[ t.sshift ];
else
set = t.G0123L[ t.leftright[ (c1&0x80) >> 7 ] ];
if( set == SUPP && (c1 & 0x70) == 0x40 ) /* diacritical ??? */
{
LOG(("diacritical mark %d\n", c1 & 0x0f));
c2 = layer2getc();
if(c2&0x60)
c1 = (c1<<8) | c2;
t.sshift = 0;
}
LOG(("OUTPUT 0x%02x '%c'\n", c1&0xff, isprint(c1&0xff) ? c1&0xff : '.'));
output(c1);
t.lastchar = c1;
}
}
return dct;
}
/*
* get one byte from protocol layer 2.
*/
int BTXService::layer2getc()
{
LONG Value;
UBYTE c;
/* is there a pushed back character ? */
if(pushback >= 0)
{
Value = App->DispatchDisplayEvent();
if(Value == CHANNELERR_EOF)
reachedEOF = 1;
c = (UBYTE)pushback;
pushback = -1;
}
else
{
while(!reachedEOF)
{
Value = App->DispatchEvent();
switch(Value)
{
case CHANNELERR_EOF:
reachedEOF = 1;
return(US);
case CHANNELERR_Timeout:
case CHANNELERR_Nothing:
App->WaitEvent();
continue;
}
if(Value < 0)
reachedEOF = 1;
else
{
c = (UBYTE)Value;
#ifdef USE_PROTOCOL
if(protocolfile)
fputc(c,protocolfile);
#endif
}
break;
}
if(reachedEOF)
c = US;
}
if(reachedEOF)
App->EventExit();
LOG(("(%c %03x %2d/%2d %2x/%2x) (0x%02x) ", t.serialmode ? 'S' : 'P',
t.serialmode ? screen[t.cursory-1][t.cursorx-1].attr : t.par_attr,
t.cursory, t.cursorx,
t.serialmode ? screen[t.cursory-1][t.cursorx-1].fg : t.par_fg,
t.serialmode ? screen[t.cursory-1][t.cursorx-1].bg : t.par_bg, c));
return c;
}
/*
* unget character 'c'. Only one character of pushback is possible !
*/
void BTXService::layer2ungetc(int c)
{
if(pushback < 0)
{
pushback = c;
LOG(("<-- character pushed back\n"));
}
else
ERRLOG(("XBTX: internal error: ungetc-buffer overflow !\n"));
}
/*
* initialize default character sets (page 113)
*/
void BTXService::default_sets()
{
t.G0123L[G0] = PRIM;
t.G0123L[G1] = SUP2;
t.G0123L[G2] = SUPP;
t.G0123L[G3] = SUP3;
t.G0123L[ L] = L; /* always L !!! (cannot be changed) */
t.leftright[0] = G0;
t.leftright[1] = G2;
t.sshift = 0;
t.save_left = G0;
t.prim = G0;
t.supp = G2;
}
/*
* move the cursor, perform automatic wraparound (page 97)
* and implicite scrolling (page 101)
*/
void BTXService::move_cursor(int cmd, int y, int x)
{
int up=0, down=0;
/* erase old cursor */
if(t.cursor_on) AppDisplay->xcursor(t.cursorx-1, t.cursory-1);
/* move & wrap */
switch(cmd) {
case APF:
if(++t.cursorx > 40)
if(t.wrap) { t.cursorx-=40; down=1; }
else t.cursorx=40;
break;
case APB:
if(--t.cursorx < 1)
if(t.wrap) { t.cursorx+=40; up=1; }
else t.cursorx=1;
break;
case APU: up=1; break;
case APD: down=1; break;
case APR: t.cursorx=1; break;
case APA:
t.hold_mosaic = 0;
if(t.wrap) { /* wrap !! (SKY-NET *200070000000004a#) */
if(x < 1) { x += 40; y--; }
if(x > 40) { x -= 40; y++; }
if(y < 1) y += rows;
if(y > rows) y -= rows;
}
else {
if(x < 1) x = 1;
if(x > 40) x = 40;
if(y < 1) y = 1;
if(y > rows) y = rows;
}
t.cursorx=x;
t.cursory=y;
break;
}
if(up) {
t.hold_mosaic = 0;
if(t.scroll_area && t.scroll_impl &&
t.cursory == t.scroll_upper) scroll(0);
else
if(--t.cursory < 1)
if(t.wrap) t.cursory += rows;
else t.cursory = 1;
}
if(down) {
t.hold_mosaic = 0;
if(t.scroll_area && t.scroll_impl &&
t.cursory == t.scroll_lower) scroll(1);
else
if(++t.cursory > rows)
if(t.wrap) t.cursory -= rows;
else t.cursory = rows;
}
/* draw new cursor */
if(t.cursor_on) AppDisplay->xcursor(t.cursorx-1, t.cursory-1);
}
/*
* process a code from the primary control set C0 (0x00 - 0x1f).
* Returns 1 when DCT is received, else 0.
*/
int BTXService::primary_control_C0(int c1) /* page 118, annex 6 */
{
int c2, x, y;
switch(c1) {
case APB:
LOG(("APB active position back\n"));
move_cursor(APB);
break;
case APF:
LOG(("APF active position forward\n"));
move_cursor(APF);
break;
case APD:
LOG(("APD active position down\n"));
move_cursor(APD);
break;
case APU:
LOG(("APU active position up\n"));
move_cursor(APU);
break;
case CS:
LOG(("CS clear screen\n"));
t.leftright[0] = t.save_left;
clearscreen();
break;
case APR:
LOG(("APR active position return\n"));
move_cursor(APR);
break;
case LS1:
case LS0:
c2 = (c1==LS1) ? 1 : 0;
LOG(("LS%d locking shift G%d left\n", c2, c2));
t.leftright[0] = c2; /* G0 or G1 !! */
t.save_left = c2;
break;
case CON:
LOG(("CON cursor on\n"));
if(!t.cursor_on) {
t.cursor_on = 1;
AppDisplay->xcursor(t.cursorx-1, t.cursory-1);
}
break;
case RPT:
LOG(("RPT repeat last char\n"));
c2 = layer2getc() & 0x3f;
LOG((" %d times\n", c2));
while(c2--) output(t.lastchar);
break;
case COF:
LOG(("COF cursor off\n"));
if(t.cursor_on) {
t.cursor_on = 0;
AppDisplay->xcursor(t.cursorx-1, t.cursory-1);
}
break;
case CAN:
LOG(("CAN cancel\n"));
y = t.cursory-1;
screen[y][t.cursorx-1].chr = ' ';
screen[y][t.cursorx-1].set = PRIM;
for(x=t.cursorx; x<40; x++) { /* clear to the right */
screen[y][x].chr = ' ';
screen[y][x].set = PRIM;
screen[y][x].mark = 0;
screen[y][x].attr = screen[y][t.cursorx-1].attr;
screen[y][x].fg = screen[y][t.cursorx-1].fg;
screen[y][x].bg = screen[y][t.cursorx-1].bg;
}
for(x=t.cursorx-1; x<40; x++) redrawc(x+1, y+1);
break;
case SS2:
LOG(("SS2 single shift G2 left\n"));
t.sshift = G2;
break;
case ESC:
LOG(("ESC escape sequence\n"));
do_ESC();
break;
case SS3:
LOG(("SS3 single shift G3 left\n"));
t.sshift = G3;
break;
case APH:
LOG(("APH active position home\n"));
move_cursor(APA, 1, 1);
t.par_attr = 0;
t.par_fg = WHITE;
t.par_bg = TRANSPARENT;
break;
case US:
LOG(("US unit separator (or APA)\n"));
do_US();
break;
default:
LOG(("??? unprocessed control character 0x%02x - ignored\n", c1));
if(c1 == DCT) return 1;
}
return 0;
}
/*
* process a code from the supplementary control set C1 (0x80 - 0x9f).
* 'fullrow' indicates attribute application to the complete row.
* Most codes advance active cursor position by one !
*/
void BTXService::supplementary_control_C1(int c1, int fullrow) /* page 121, annex 6 */
{
int adv, mode = fullrow ? 2 : t.serialmode;
switch(c1) {
/* serial parallel */
case 0x80: /* ABK BKF */
case 0x81: /* ANR RDF */
case 0x82: /* ANG GRF */
case 0x83: /* ANY YLF */
case 0x84: /* ANB BLF */
case 0x85: /* ANM MGF */
case 0x86: /* ANC CNF */
case 0x87: /* ANW WHF */
LOG(("set foreground to color #%d %s\n", t.clut*8+c1-0x80,
(mode==1) ? "(+ unload L set)" : ""));
set_attr(ATTR_FOREGROUND, 1, t.clut*8+c1-0x80, mode);
if(mode==1) {
t.leftright[0] = t.save_left;
}
break;
case FSH:
LOG(("FSH flashing begin\n"));
/* set_attr(ATTR_FLASH, 1, 0, mode); */
break;
case STD:
LOG(("STD flashing steady\n"));
/* set_attr(ATTR_FLASH, 0, 0, mode); */
break;
case EBX:
LOG(("EBX end of window\n"));
/* set_attr(ATTR_WINDOW, 0, 0, mode); */
break;
case SBX:
LOG(("SBX start of window\n"));
/* set_attr(ATTR_WINDOW, 1, 0, mode); */
break;
case NSZ:
LOG(("NSZ normal size\n"));
set_attr(ATTR_NODOUBLE, 1, 0, mode);
break;
case DBH:
LOG(("DBH double height\n"));
set_attr(ATTR_YDOUBLE, 1, 0, mode);
break;
case DBW:
LOG(("DBW double width\n"));
set_attr(ATTR_XDOUBLE, 1, 0, mode);
break;
case DBS:
LOG(("DBS double size\n"));
set_attr(ATTR_XYDOUBLE, 1, 0, mode);
break;
/* serial parallel */
case 0x90: /* MBK BKB */
case 0x91: /* MSR RDB */
case 0x92: /* MSG GRB */
case 0x93: /* MSY YLB */
case 0x94: /* MSB BLB */
case 0x95: /* MSM MGB */
case 0x96: /* MSC CNB */
case 0x97: /* MSW WHB */
/* at fullrow control the parallel set is used ! */
LOG(("set %s to color #%d\n", (mode==1) ?
"mosaic foreground (+ invoke L set)" : "background",
t.clut*8+c1-0x90));
if(mode==1) {
set_attr(ATTR_FOREGROUND, 1, t.clut*8+c1-0x90, 1);
t.save_left = t.leftright[0];
t.leftright[0] = L;
}
else set_attr(ATTR_BACKGROUND, 1, t.clut*8+c1-0x90, mode);
break;
case CDY:
LOG(("CDY conceal display\n"));
set_attr(ATTR_CONCEALED, 1, 0, mode);
break;
case SPL:
LOG(("SPL stop lining\n"));
set_attr(ATTR_UNDERLINE, 0, 0, mode);
break;
case STL:
LOG(("STL start lining\n"));
set_attr(ATTR_UNDERLINE, 1, 0, mode);
break;
case CSI:
LOG(("CSI control sequence introducer\n"));
adv = do_CSI();
break;
case 0x9c:
if(mode==1) {
LOG(("BBD black background\n"));
set_attr(ATTR_BACKGROUND, 1, t.clut*8+BLACK, 1);
} else {
LOG(("NPO normal polarity\n"));
set_attr(ATTR_INVERTED, 0, 0, mode);
}
break;
case 0x9d:
if(mode==1) {
LOG(("NBD new background\n"));
set_attr(ATTR_BACKGROUND, 1,
screen[t.cursory-1][t.cursorx-1].fg, 1);
} else {
LOG(("IPO inverted polarity\n"));
set_attr(ATTR_INVERTED, 1, 0, mode);
}
break;
case 0x9e:
if(mode==1) {
LOG(("HMS hold mosaic\n"));
t.hold_mosaic = 1;
} else {
LOG(("TRB transparent background\n"));
set_attr(ATTR_BACKGROUND, 1, TRANSPARENT, mode);
}
break;
case 0x9f:
if(mode==1) {
LOG(("RMS release mosaic\n"));
t.hold_mosaic = 0;
} else {
LOG(("STC stop conceal\n"));
set_attr(ATTR_CONCEALED, 0, 0, mode);
}
break;
}
/* serial attribute controls advance cursor 1 char forwards ! (page 90) */
if(mode==1 && (c1!=CSI || adv) )
if(t.hold_mosaic) output(t.lastchar); /* HMS/RMS (page 96) */
else move_cursor(APF);
}
void BTXService::do_US() /* page 85/86 */
{
static UBYTE TFI_string[] = { SOH, US, 0x20, 0x7f, 0x40, ETB };
int c2, c3, alphamosaic = 0;;
/* implicite return from service break !!! (any US sequence !?!) */
if(t.service_break) {
t = backup;
move_cursor(APA, t.cursory, t.cursorx);
}
for(;;)
{
c2 = layer2getc();
if(c2 != 0x1f)
break;
}
switch(c2) {
case 0x20: /* annex 7.3 */
LOG((" TFI Terminal Facility Identifier\n"));
c3 = layer2getc();
if(c3==0x40) {
LOG((" TFI request\n"));
write(TFI_string, 6);
}
else {
LOG((" TFI echo 0x%02x\n", c3));
do {
c3 = layer2getc();
LOG((" TFI echo 0x%02x\n", c3));
}
while(c3 & 0x20); /* extension bit */
}
break;
case 0x23:
LOG((" define DRCS\n"));
do_DRCS();
break;
case 0x26:
LOG((" define color\n"));
do_DEFCOLOR();
break;
case 0x2d: /* page 155 */
LOG((" define Format\n"));
do_DEFFORMAT();
break;
case 0x2f: /* page 157 */
LOG((" Reset sequence\n"));
do_RESET();
alphamosaic = 1;
break;
case 0x3e: /* annex 7.4 */
LOG((" telesoftware\n"));
do_Telesoftware();
alphamosaic = 0;
break;
default: /* APA active position addressing */
if(c2<0x40) LOG((" unknown US sequence\n"));
else {
alphamosaic = 1;
LOG((" new row %2d\n", c2 & 0x3f));
c3 = layer2getc();
LOG((" new column %2d\n", c3 & 0x3f));
move_cursor(APA, c2 & 0x3f, c3 & 0x3f);
t.par_attr = 0;
t.par_fg = WHITE;
t.par_bg = TRANSPARENT;
}
break;
}
/* VPDE = US x data. Each VPDE has to be followed by the next VPDE
* immediately (page 85). The alphamosaic VPDE is introduced by APA or
* by one of the reset functions ! Any remaining data (errors) after all
* other VPDE's has to be skipped (*17420101711a#).
*/
if(!alphamosaic) {
while( (c2 = layer2getc()) != US ) LOG(("skipping to next US\n"));
LOG(("\n"));
layer2ungetc(US);
}
}
void BTXService::do_ESC()
{
int y, c2, c3, c4;
c2 = layer2getc();
switch(c2) {
case 0x22:
LOG((" invoke C1\n"));
c3 = layer2getc();
LOG((" (%s)\n", c3==0x40 ? "serial" : "parallel"));
if(c3==0x40) t.serialmode = 1;
else {
t.serialmode = 0;
t.leftright[0] = t.save_left;
}
break;
case 0x23:
LOG((" set attributes\n"));
c3 = layer2getc();
switch(c3) {
case 0x20:
LOG((" full screen background\n"));
c4 = layer2getc();
LOG((" color = %d\n",
c4==0x5e ? TRANSPARENT : t.clut*8+c4-0x50));
for(y=0; y<24; y++)
AppDisplay->define_fullrow_bg(y, c4==0x5e ?
TRANSPARENT : t.clut*8+c4-0x50);
break;
case 0x21:
LOG((" full row\n"));
c4 = layer2getc();
LOG((" "));
supplementary_control_C1(c4+0x40, 1);
break;
}
break;
case 0x28:
case 0x29:
case 0x2a:
case 0x2b:
LOG((" load G%d with\n", c2 - 0x28));
c3 = layer2getc();
switch(c3) {
case 0x40:
LOG((" 'primary graphic'\n"));
t.G0123L[c2 - 0x28] = PRIM;
t.prim = c2 - 0x28;
break;
case 0x62:
LOG((" 'supplementary graphic'\n"));
t.G0123L[c2 - 0x28] = SUPP;
t.supp = c2 - 0x28;
break;
case 0x63:
LOG((" '2nd supplementary mosaic'\n"));
t.G0123L[c2 - 0x28] = SUP2;
break;
case 0x64:
LOG((" '3rd supplementary mosaic'\n"));
t.G0123L[c2 - 0x28] = SUP3;
break;
case 0x20:
LOG((" DRCS\n"));
c4 = layer2getc();
if(c4 != 0x40) LOG(("HAEH (ESC 0x%02x 0x20 0x%02x)\n", c2, c4));
else LOG(("\n"));
t.G0123L[c2 - 0x28] = DRCS;
break;
}
break;
case 0x6e:
LOG((" LS2 locking shift G2 left\n"));
t.leftright[0] = G2;
t.save_left = G2;
break;
case 0x6f:
LOG((" LS3 locking shift G3 left\n"));
t.leftright[0] = G3;
t.save_left = G3;
break;
case 0x7c:
LOG((" LS3R locking shift G3 right\n"));
t.leftright[1] = G3;
break;
case 0x7d:
LOG((" LS2R locking shift G2 right\n"));
t.leftright[1] = G2;
break;
case 0x7e:
LOG((" LS1R locking shift G1 right\n"));
t.leftright[1] = G1;
break;
}
}
/*
* Process one control sequence. Return whether or not the cursor position
* has to be advanced by one char (in case of serialmode).
*
* Anscheinend sollen nur die FLASH-controls den Cursor eins weiterstellen -
* steht zwar nirgends, sieht aber am besten aus !!!
*/
int BTXService::do_CSI()
{
int c2, c3, upper, lower;
c2 = layer2getc();
if(c2 == 0x42) {
LOG((" STC stop conceal\n"));
set_attr(ATTR_CONCEALED, 0, 0, t.serialmode);
return 0;
}
LOG(("\n"));
c3 = layer2getc();
/* protection only available as fullrow controls ?? (page 135) */
if(c2 == 0x31 && c3 == 0x50) {
LOG((" PMS protected mode start\n"));
set_attr(ATTR_PROTECTED, 1, 0, 2);
return 0;
}
if(c2 == 0x31 && c3 == 0x51) {
LOG((" PMC protected mode cancel\n"));
set_attr(ATTR_PROTECTED, 0, 0, 2);
return 0;
}
if(c2 == 0x32 && c3 == 0x53) {
LOG((" MMS marked mode start\n"));
/* set_attr(ATTR_MARKED, 1, 0, t.serialmode); */
return 0;
}
if(c2 == 0x32 && c3 == 0x54) {
LOG((" MMT marked mode stop\n"));
/* set_attr(ATTR_MARKED, 0, 0, t.serialmode); */
return 0;
}
switch(c3) {
case 0x40:
LOG((" invoke CLUT%d\n", c2 - 0x2f));
t.clut = c2 - 0x30;
return 0;
case 0x41:
switch(c2) {
case 0x30:
LOG((" IVF inverted flash\n"));
return 1;
case 0x31:
LOG((" RIF reduced intesity flash\n"));
return 1;
case 0x32:
case 0x33:
case 0x34:
LOG((" FF%c fast flash %c\n", c2-1, c2-1));
return 1;
case 0x35:
LOG((" ICF increment flash\n"));
return 1;
case 0x36:
LOG((" DCF decrement flash\n"));
return 1;
}
break;
case 0x60:
switch(c2) {
case 0x30:
LOG((" SCU explicit scroll up\n"));
if(t.scroll_area) scroll(1);
return 0;
case 0x31:
LOG((" SCD explicit scroll down\n"));
if(t.scroll_area) scroll(0);
return 0;
case 0x32:
LOG((" AIS activate implicite scrolling\n"));
t.scroll_impl = 1;
return 0;
case 0x33:
LOG((" DIS deactivate implicite scrolling\n"));
t.scroll_impl = 0;
return 0;
}
break;
default: /* definition of scrolling area (page 137) */
upper = c2 & 0x0f;
if(c3>=0x30 && c3<=0x39) upper = upper*10 + (c3&0x0f);
LOG((" upper row: %2d\n", upper));
if(c3>=0x30 && c3<=0x39) { c3 = layer2getc(); LOG(("\n")); }
if(c3!=0x3b) ERRLOG(("XBTX: scrolling area - protocol !\n"));
lower = layer2getc() & 0x0f;
LOG(("\n"));
c3 = layer2getc();
if(c3>=0x30 && c3<=0x39) lower = lower*10 + (c3&0x0f);
LOG((" lower row: %2d", lower));
if(c3>=0x30 && c3<=0x39) { LOG(("\n")); c3=layer2getc(); LOG((" ")); }
if(c3==0x55) {
LOG((" CSA create scrolling area\n"));
if(upper>=2 && lower<rows && lower>=upper) {
t.scroll_upper = upper;
t.scroll_lower = lower;
t.scroll_area = 1;
}
}
if(c3==0x56) {
LOG((" CSD delete scrolling area\n"));
t.scroll_area = 0;
}
return 0;
}
return 0;
}
void BTXService::do_DRCS() /* (page 139ff) */
{
int c3, c4, c5, c6, c7, c8;
c3 = layer2getc();
if(c3 == 0x20) {
LOG((" DRCS header unit\n"));
c4 = layer2getc();
if(c4==0x20 || c4==0x28) {
LOG((" %s existing DRCS\n", (c4==0x20) ? "keep" : "delete"));
if(c4==0x28) AppDisplay->free_DRCS();
c5 = layer2getc();
} else c5 = c4;
if(c5 == 0x20) {
LOG(("\n"));
c6 = layer2getc();
} else c6 = c5;
if(c6 == 0x40) {
LOG(("\n"));
c7 = layer2getc();
} else c7 = c6;
switch(c7 & 0xf) {
case 6:
LOG((" 12x12 pixel\n"));
t.drcs_w = 12;
t.drcs_h = 12;
break;
case 7:
LOG((" 12x10 pixel\n"));
t.drcs_w = 12;
t.drcs_h = 10;
break;
case 10:
LOG((" 6x12 pixel\n"));
t.drcs_w = 6;
t.drcs_h = 12;
break;
case 11:
LOG((" 6x10 pixel\n"));
t.drcs_w = 6;
t.drcs_h = 10;
break;
case 12:
LOG((" 6x5 pixel\n"));
t.drcs_w = 6;
t.drcs_h = 5;
break;
case 15:
LOG((" 6x6 pixel\n"));
t.drcs_w = 6;
t.drcs_h = 6;
break;
}
c8 = layer2getc();
LOG((" %d bit/pixel\n", c8 & 0xf));
t.drcs_bits = c8 & 0xf;
t.drcs_step = (t.drcs_h>=10 && t.drcs_w*t.drcs_bits==24) ? 2 : 1;
}
else {
LOG((" DRCS pattern transfer unit (char: 0x%02x)\n", c3));
do_DRCS_data(c3);
}
}
/*
* load and define dynamic characters, first character is 'c'.
* more than one bitplane of a character may be loaded simultaneously !
*/
void BTXService::do_DRCS_data(int c)
{
int c4, i, n, planes=0, planemask=0, byte=0;
int maxbytes, start = c;
maxbytes = 2*t.drcs_h;
if(t.drcs_h<10) maxbytes *= 2;
memset(data,0,sizeof(data));
do {
c4 = layer2getc();
switch(c4) {
case 0x20: /* S-bytes */
case 0x2f:
LOG((" fill rest of char with %d\n", c4 & 1));
for(; byte<maxbytes; byte++)
for(n=0; n<4; n++)
if(planemask & (1<<n)) data[n][byte] = (UBYTE)((c4==0x20) ? 0 : 0xff);
break;
case 0x21:
case 0x22:
case 0x23:
case 0x24:
case 0x25:
case 0x26:
case 0x27:
case 0x28:
case 0x29:
case 0x2a:
LOG((" repeat last row %d times\n", c4 & 0xf));
if(byte&1) byte++; /* pad to full row (assume 0) */
for(i=0; i<(c4 & 0xf); i++) {
for(n=0; n<4; n++)
if(planemask & (1<<n)) {
data[n][byte] = (UBYTE)(byte ? data[n][byte-2] : 0);
data[n][byte+1] = (UBYTE)(byte ? data[n][byte-2+1] : 0);
if(t.drcs_h<10) {
data[n][byte+2] = (UBYTE)(byte ? data[n][byte-2] : 0);
data[n][byte+3] = (UBYTE)(byte ? data[n][byte-2+1] : 0);
}
}
byte += 2;
if(t.drcs_h<10) byte += 2;
}
break;
case 0x2c:
case 0x2d:
LOG((" full row %d\n", c4 & 1));
if(byte&1) byte++; /* pad to full row (assume 0) */
for(n=0; n<4; n++)
if(planemask & (1<<n)) {
data[n][byte] = (UBYTE)((c4==0x2c) ? 0 : 0xff);
data[n][byte+1] = (UBYTE)((c4==0x2c) ? 0 : 0xff);
if(t.drcs_h<10) {
data[n][byte+2] = (UBYTE)((c4==0x2c) ? 0 : 0xff);
data[n][byte+3] = (UBYTE)((c4==0x2c) ? 0 : 0xff);
}
}
byte += 2;
if(t.drcs_h<10) byte += 2;
break;
case 0x2e:
LOG((" fill rest of char with last row\n"));
if(byte&1) byte++; /* pad to full row (assume 0) */
while(byte<maxbytes) {
for(n=0; n<4; n++)
if(planemask & (1<<n)) {
data[n][byte] = data[n][byte-2];
data[n][byte+1] = data[n][byte-2+1];
}
byte += 2;
}
break;
case 0x30: /* B-bytes */
case 0x31:
case 0x32:
case 0x33:
if(byte) {
LOG((" new plane ahead - filling up\n"));
byte = maxbytes; /* pad to full plane */
layer2ungetc(c4);
}
else {
LOG((" start of pattern block (plane %d)\n", c4 & 0xf));
for(i=0; i<2*FONT_HEIGHT; i++) data[c4 & 0xf][i] = 0;
planemask |= 1 << (c4 & 0xf);
}
break;
default:
if(c4<0x20 || c4>0x7f) {
LOG((" end of pattern data\n"));
layer2ungetc(c4);
if(byte) byte = maxbytes;
}
else { /* D-bytes */
LOG((" pattern data\n"));
if(t.drcs_w==6) { /* low res */
for(n=0; n<4; n++)
if(planemask & (1<<n)) {
data[n][byte] =
(UBYTE)(((c4&32)?0x30:0) | ((c4&16)?0x0c:0) | ((c4&8)?0x03:0));
data[n][byte+1] =
(UBYTE)(((c4&4)?0x30:0) | ((c4&2)?0x0c:0) | ((c4&1)?0x03:0));
}
byte += 2;
}
else {
for(n=0; n<4; n++)
if(planemask & (1<<n)) data[n][byte] = (UBYTE)(c4 & 0x3f);
byte++;
}
if(!(byte&1) && t.drcs_h<10) { /* duplicate row ? */
for(n=0; n<4; n++)
if(planemask & (1<<n)) {
data[n][byte] = data[n][byte-2];
data[n][byte+1] = data[n][byte-2+1];
}
byte += 2;
}
}
break;
} /* switch */
if(byte == maxbytes) { /* plane is complete */
for(n=0; n<4; n++) if(planemask & (1<<n)) planes++;
planemask = 0;
byte = 0;
if(planes == t.drcs_bits) { /* DRC is complete */
log_DRC(c, t.drcs_bits);
AppDisplay->define_raw_DRC(c, &data[0][0], t.drcs_bits);
planes = 0;
c += t.drcs_step;
}
}
} while(c4>=0x20 && c4<=0x7f);
update_DRCS_display(start, c, t.drcs_step);
}
/*
* pretty print the received character to the LOG file
*/
void BTXService::log_DRC(int c, int bits)
{
int n, i, j, k;
LOG(("\n DRC # 0x%2x\n", c));
for(n=0; n<bits; n++) {
LOG((" (plane %d)\n", n));
LOG((" --------------------------\n"));
for(j=0; j<fontheight; j++) {
LOG((" |"));
for(k=0; k<2; k++)
for(i=5; i>=0; i--)
if(data[n][j*2+k] & (1<<i)) LOG(("* "));
else LOG((" "));
LOG(("|\n"));
}
LOG((" --------------------------\n\n"));
}
}
/*
* load and define dynamic colors.
*/
void BTXService::do_DEFCOLOR() /* (page 150ff) */
{
int c3, c4, c5, c6, c7, index, r, g, b;
c3 = layer2getc();
switch(c3) {
case 0x20: /* US 0x26 0x20 <ICT> <SUR> <SCM> */
LOG((" color header unit\n"));
t.col_modmap = 1; /* by default modify colormap */
c4 = layer2getc();
if((c4 & 0xf0) == 0x20) {
if(c4!=0x20 && c4!=0x22) {
LOG(("*** <ICT>: bad value !\n"));
ERRLOG(("XBTX: do_DEFCOLOR(): ICT1 = 0x%02x\n", c4));
}
LOG((" <ICT>: load %s\n", c4==0x20 ? "colormap" : "DCLUT"));
t.col_modmap = (c4==0x20);
c5 = layer2getc();
} else c5 = c4;
if((c5 & 0xf0) == 0x20) {
LOG((" <ICT>: (unit %d)\n", c5&0xf));
if(c5!=0x20) {
LOG(("*** <ICT>: bad value !\n"));
ERRLOG(("XBTX: do_DEFCOLOR(): ICT2 = 0x%02x\n", c5));
}
c6 = layer2getc();
} else c6 = c5;
if((c6 & 0xf0) == 0x30) {
LOG((" <SUR>: %d bits\n", c6&0xf));
if(c6!=0x34 && c6!=0x35) {
LOG(("*** <SUR>: bad value !\n"));
ERRLOG(("XBTX: do_DEFCOLOR(): SUR = 0x%02x\n", c6));
}
c7 = layer2getc();
} else c7 = c6;
if((c7 & 0xf0) == 0x40) {
LOG((" <SCM>: 0x%02x\n", c7));
if(c7!=0x40 && c7!=0x41) {
LOG(("*** <SCM>: bad value !\n"));
ERRLOG(("XBTX: do_DEFCOLOR(): SCM = 0x%02x\n", c7));
}
} else {
LOG((" default header\n"));
layer2ungetc(c7);
}
break;
case 0x21:
LOG((" color reset unit\n"));
AppDisplay->default_colors();
break;
default:
LOG((" color transfer unit (1.Stelle: %d)\n", c3&0xf));
index = c3&0xf;
c4 = layer2getc();
if((c4 & 0xf0) == 0x30) { /* c3 zehner, c4 einer */
LOG((" (2.Stelle: %d)\n", c4&0xf));
index = (c3&0xf)*10 + (c4&0xf);
c5 = layer2getc();
} else c5 = c4;
if(t.col_modmap) { /* load colormap */
while(c5>=0x40 && c5<=0x7f) {
LOG((" color #%2d: R G B\n", index));
c6 = layer2getc();
r = (c5&0x20)>>2 | (c5&0x04) | (c6&0x20)>>4 | (c6&0x04)>>2;
g = (c5&0x10)>>1 | (c5&0x02)<<1 | (c6&0x10)>>3 | (c6&0x02)>>1;
b = (c5&0x08) | (c5&0x01)<<2 | (c6&0x08)>>2 | (c6&0x01);
LOG((" %1x %1x %1x\n", r, g, b));
if(index>=16 && index<=31) AppDisplay->define_color(index++, r, g, b);
c5 = layer2getc();
}
}
else { /* load DCLUT */
while(c5>=0x40 && c5<=0x7f) {
LOG((" DCLUT[%2d] = %2d\n", index, c5&0x1f));
if(index>=0 && index<=3) AppDisplay->define_DCLUT(index++, c5&0x1f);
c5 = layer2getc();
}
}
LOG((" end of color data\n"));
layer2ungetc(c5);
break;
}
}
void BTXService::do_DEFFORMAT() /* format designation (page 155) */
{
int c3, c4;
rows = 24;
fontheight = 10;
t.wrap = 1;
c3 = layer2getc();
if((c3&0xf0) == 0x40) {
switch(c3) {
case 0x41:
LOG((" 40 columns by 24 rows\n"));
break;
case 0x42:
LOG((" 40 columns by 20 rows\n"));
rows = 20;
fontheight = 12;
break;
default:
LOG((" unrecognized format (using default)\n"));
break;
}
c4 = layer2getc();
}
else c4 = c3;
if((c4&0xf0) == 0x70) {
LOG((" wraparound %s\n", (c3&1) ? "inactive" : "active"));
t.wrap = (c3 == 0x70) ? 1 : 0;
}
else {
LOG((" default format\n"));
layer2ungetc(c4);
}
}
void BTXService::do_RESET() /* reset functions (page 157) */
{
int y, c3, c4;
c3 = layer2getc();
switch(c3) {
case 0x40: /* (page 158) */
LOG((" service break to row\n"));
c4 = layer2getc();
LOG((" #%d\n", c4 & 0x3f));
backup = t; /* structure copy */
t.leftright[0] = t.prim; /* PFUSCH !!! */
t.leftright[1] = t.supp;
t.save_left = t.prim;
t.wrap = 0;
t.cursor_on = 0;
move_cursor(APA, c4 & 0x3f, 1);
t.serialmode = 1;
t.clut = 0;
t.service_break = 1;
break;
case 0x41:
case 0x42:
LOG((" defaults (%s C1)\n", c3&1 ? "serial" : "parallel"));
default_sets();
t.serialmode = c3 & 1;
t.wrap = 1;
t.cursor_on = 0;
rows = 24;
fontheight = 10;
for(y=0; y<24; y++) AppDisplay->define_fullrow_bg(y, BLACK);
clearscreen(); /* clearscr resets CLUT, par_attr, cursor pos */
break;
case 0x43:
case 0x44:
LOG((" limited defaults (%s C1)\n", c3&1 ? "serial":"parallel"));
default_sets();
t.serialmode = c3 & 1;
break;
case 0x4f:
LOG((" reset to previous state\n"));
t = backup;
move_cursor(APA, t.cursory, t.cursorx);
break;
}
}
/*
* set/reset parallel, serial or fullrow attributes (+ set/delete markers)
* (mode: 0=parallel, 1=serial, 2=fullrow)
*
* MARKER: (page 91 / annex 1, page 29)
*
* parallel: (set in output())
* set wherever an attr is changed
* set at attr changes in writing a continuous string
* delete existing markers in overwritten part of "
* delete when printing and attrs do not change
*
* serial: (set here)
* set at this position
*/
void BTXService::set_attr(int a, int set, int col, int mode)
{
int x, y = t.cursory-1, refresh, mattr = a;
/* set fullrow background */
if(mode==2 && a==ATTR_BACKGROUND) {
AppDisplay->define_fullrow_bg(y, col);
return;
}
if(a & ATTR_ANYSIZE) mattr = ATTR_SIZE;
/* serial mode controls set a marker */
if(mode==1) screen[y][t.cursorx-1].mark |= mattr;
/* serial/fullrow controls apply to parts of the row */
if(mode) { /* serial || fullrow */
/* receiption of serial DBS/DBH in last row of scrolling area */
/* forces a scroll up + a cursor up before writing (page 101) */
if( (t.service_break || !(screen[y][0].attr & ATTR_PROTECTED)) &&
(a==ATTR_YDOUBLE || a==ATTR_XYDOUBLE) &&
t.scroll_area && t.cursory==t.scroll_lower) {
scroll(1);
move_cursor(APU);
y = t.cursory-1;
}
x = (mode==2) ? 0 : t.cursorx-1;
do {
refresh = 0;
/* fullrow controls delete the marker in the complete row */
if(mode==2) screen[y][x].mark &= ~mattr;
if( t.service_break || !(screen[y][x].attr & ATTR_PROTECTED) ||
(a==ATTR_PROTECTED && set==0) ) {
switch(a) {
case ATTR_NODOUBLE:
if(screen[y][x].attr & (ATTR_XDOUBLE|ATTR_YDOUBLE))
refresh = 1;
screen[y][x].attr &= ~(ATTR_XDOUBLE|ATTR_YDOUBLE);
break;
case ATTR_XYDOUBLE:
if((screen[y][x].attr & (ATTR_XDOUBLE|ATTR_YDOUBLE)) !=
(ATTR_XDOUBLE|ATTR_YDOUBLE) ) refresh = 1;
screen[y][x].attr |= (ATTR_XDOUBLE|ATTR_YDOUBLE);
break;
case ATTR_XDOUBLE:
if((screen[y][x].attr & (ATTR_XDOUBLE|ATTR_YDOUBLE)) !=
ATTR_XDOUBLE ) refresh = 1;
screen[y][x].attr &= ~ATTR_YDOUBLE;
screen[y][x].attr |= ATTR_XDOUBLE;
break;
case ATTR_YDOUBLE:
if((screen[y][x].attr & (ATTR_XDOUBLE|ATTR_YDOUBLE)) !=
ATTR_YDOUBLE ) refresh = 1;
screen[y][x].attr &= ~ATTR_XDOUBLE;
screen[y][x].attr |= ATTR_YDOUBLE;
break;
case ATTR_FOREGROUND:
if(screen[y][x].fg!=col && screen[y][x].chr!=' ') refresh=1;
screen[y][x].fg = (UBYTE)col;
break;
case ATTR_BACKGROUND:
if(screen[y][x].bg != col) refresh = 1;
screen[y][x].bg = (UBYTE)col;
break;
default:
if( ((screen[y][x].attr & a)>0) != set ) refresh = 1;
if(set) screen[y][x].attr |= a;
else screen[y][x].attr &= ~a;
break;
} /* switch */
if(refresh) redrawc(x+1, y+1);
/* (DBH/DBS chars must not cross borders of a protected area) */
if(a==ATTR_PROTECTED && y && realattr(y, x+1, ATTR_YDOUBLE) &&
attrib(y, x+1, a) != attrib(y+1, x+1, a) ) redrawc(x+1, y);
} /* if !protected */
x++;
} /* while x<40 && (serialmode --> no marker set) */
while(x<40 && (mode!=1 || !(screen[y][x].mark & mattr)) );
}
else { /* parallel */
switch(a) {
case ATTR_NODOUBLE:
t.par_attr &= ~(ATTR_XDOUBLE|ATTR_YDOUBLE);
break;
case ATTR_XYDOUBLE:
t.par_attr |= (ATTR_XDOUBLE|ATTR_YDOUBLE);
break;
case ATTR_XDOUBLE:
t.par_attr &= ~ATTR_YDOUBLE;
t.par_attr |= ATTR_XDOUBLE;
break;
case ATTR_YDOUBLE:
t.par_attr &= ~ATTR_XDOUBLE;
t.par_attr |= ATTR_YDOUBLE;
break;
case ATTR_FOREGROUND:
t.par_fg = col;
break;
case ATTR_BACKGROUND:
t.par_bg = col;
break;
default:
if(set) t.par_attr |= a;
else t.par_attr &= ~a;
break;
}
}
}
/*
* output character c from current set at current cursor position.
*/
void BTXService::output(int c)
{
int xd, yd, set, mattr, x = t.cursorx, y = t.cursory;
/* select active character set */
if(t.sshift) set = t.G0123L[ t.sshift ];
else set = t.G0123L[ t.leftright[ (c&0x80) >> 7 ] ];
if(t.serialmode) {
xd = attrib(y, x, ATTR_XDOUBLE);
yd = attrib(y, x, ATTR_YDOUBLE);
/* update screen memory (if not protected) */
if( t.service_break || !attrib(y, x, ATTR_PROTECTED) ) {
screen[y-1][x-1].chr = (unsigned short)(c & ~0x80);
screen[y-1][x-1].set = (UBYTE)set;
redrawc(x, y);
}
}
else { /* parallel */
xd = (t.par_attr & ATTR_XDOUBLE) > 0;
yd = (t.par_attr & ATTR_YDOUBLE) > 0;
if(y<2) yd = 0;
/* if not protected, (scroll +) update memory */
if( t.service_break || !attrib(y, x, ATTR_PROTECTED) ) {
/* parallel DBS/DBH chars in first row of scrolling area */
/* force a scroll down + a cursor down before writing (page 101) */
if(yd && t.scroll_area && y==t.scroll_upper) {
scroll(0);
move_cursor(APD);
y = t.cursory;
}
/* update screen memory
* if no DBS/DBH in the first row or in the row below a protected area
* if no DBS/DBH in the row below a scrolling area (page 99)
*/
if( !(yd && !t.service_break && attrib(y-1, x, ATTR_PROTECTED)) &&
!(yd && t.scroll_area && y==t.scroll_lower+1) ) {
/* parallel DBH/DBS chars extent upwards, write in the row above */
if(yd) y--;
screen[y-1][x-1].chr = (unsigned short)(c & ~0x80);
screen[y-1][x-1].set = (UBYTE)set;
screen[y-1][x-1].fg = (UBYTE)t.par_fg;
screen[y-1][x-1].bg = (UBYTE)t.par_bg;
screen[y-1][x-1].attr = (unsigned short)t.par_attr;
/* par. DBS/DBW attrs apply also to the next char ! (page 106) */
if(xd && x<40) screen[y-1][x].attr = (unsigned short)t.par_attr;
mattr = t.par_attr & ~ATTR_ANYSIZE;
if(t.par_attr & ATTR_ANYSIZE) mattr |= ATTR_SIZE;
if(x>1) { /* set/reset markers */
screen[y-1][x-1].mark = (unsigned short)(screen[y-1][x-1-1].attr ^ mattr);
screen[y-1][x-1].mark &= ~(ATTR_FOREGROUND|ATTR_BACKGROUND);
if(screen[y-1][x-1-1].fg!=t.par_fg)
screen[y-1][x-1].mark |= ATTR_FOREGROUND;
if(screen[y-1][x-1-1].bg!=t.par_bg)
screen[y-1][x-1].mark |= ATTR_BACKGROUND;
}
if(x<40) { /* set/reset markers */
screen[y-1][x].mark = (unsigned short)(mattr ^ screen[y-1][x].attr);
screen[y-1][x].mark &= ~(ATTR_FOREGROUND|ATTR_BACKGROUND);
if(screen[y-1][x].fg!=t.par_fg)
screen[y-1][x].mark |= ATTR_FOREGROUND;
if(screen[y-1][x].bg!=t.par_bg)
screen[y-1][x].mark |= ATTR_BACKGROUND;
}
redrawc(x, y);
} /* scrolling/protected area */
} /* if not protected */
} /* if serial / parallel */
if(xd && t.cursorx<40) move_cursor(APF);
move_cursor(APF);
t.sshift = 0;
}
/*
* redraws character at screen position x, y (1 based !),
* if not concealed or obscured
*/
void BTXService::redrawc(int x, int y)
{
// extern int reveal;
int c, set, xd, yd, up_in=0, dn_in=0;
unsigned int real, xreal, yreal, xyreal;
/* check whether attributes are valid */
xd = attrib(y, x, ATTR_XDOUBLE);
yd = attrib(y, x, ATTR_YDOUBLE);
if(x>=40) xd = 0;
if(y>=rows) yd = 0;
/* check whether origin is obscured */
if( (y>1 && realattr(y-1, x, ATTR_YDOUBLE)) ||
(x>1 && realattr(y, x-1, ATTR_XDOUBLE)) ||
(y>1 && x>1 && realattr(y-1, x-1, ATTR_XDOUBLE) &&
realattr(y-1, x-1, ATTR_YDOUBLE)) ) {
screen[y-1][x-1].real = 0;
}
else {
/* check whether DBW char is partially obscured */
if(xd && y>1 && x<40 && realattr(y-1, x+1, ATTR_YDOUBLE)) xd = 0;
/* check whether char crosses borders of scrolling area (page 99) */
if(yd && t.scroll_area) {
if(y >=t.scroll_upper && y <=t.scroll_lower) up_in=1;
if(y+1>=t.scroll_upper && y+1<=t.scroll_lower) dn_in=1;
if(up_in != dn_in) yd = 0;
}
/* check whether char crosses borders of protected area (page 110) */
if(yd && attrib(y, x, ATTR_PROTECTED) !=
attrib(y+1, x, ATTR_PROTECTED) ) yd=0;
/* concealed characters are drawn as SPACES (page 109) */
// if(!reveal && attrib(y, x, ATTR_CONCEALED)) { c=' '; set=PRIM; }
// else {
c = screen[y-1][x-1].chr & 0x7f;
set = screen[y-1][x-1].set;
// }
/* now really display the character in the remaining size */
AppDisplay->xputc(c, set, x-1, y-1, xd, yd,
attrib(y, x, ATTR_UNDERLINE),
(screen[y-1][x-1].chr>>8) & 0x7f,
attrib(y, x, ATTR_INVERTED) ? attr_bg(y, x) : attr_fg(y, x),
attrib(y, x, ATTR_INVERTED) ? attr_fg(y, x) : attr_bg(y, x) );
if(t.cursor_on && x==t.cursorx && y==t.cursory) AppDisplay->xcursor(x-1, y-1);
/* update 'real' attributes */
real = screen[y-1][x-1].real;
screen[y-1][x-1].real = (unsigned short)(screen[y-1][x-1].attr & ~ATTR_ANYSIZE);
if(xd) {
screen[y-1][x-1].real |= ATTR_XDOUBLE;
xreal = screen[y-1][x].real;
screen[y-1][x].real = 0;
}
if(yd) {
screen[y-1][x-1].real |= ATTR_YDOUBLE;
yreal = screen[y][x-1].real;
screen[y][x-1].real = 0;
}
if(xd && yd) {
xyreal = screen[y][x].real;
screen[y][x].real = 0;
}
/* redraw (indirect recursion !!) neighbours */
updatec(real, x, y);
if(xd) updatec(xreal, x+1, y);
if(yd) updatec(yreal, x, y+1);
if(xd && yd) updatec(xyreal, x+1, y+1);
/* redraw an enlarged char to the left (now partially obscured !) */
if(yd && x>1 && realattr(y+1, x-1, ATTR_XDOUBLE)) redrawc(x-1, y+1);
} /* origin obscured */
}
/*
* this character has been obscured. check whether it was an enlarged char
* and therefor its neighbours have to be redrawn.
*/
void BTXService::updatec(int real, int x, int y)
{
if(real & ATTR_XDOUBLE) redrawc(x+1, y);
if(real & ATTR_YDOUBLE) redrawc(x, y+1);
if( (real & ATTR_XDOUBLE) && (real & ATTR_YDOUBLE) ) redrawc(x+1, y+1);
}
/*
* redraw rectangle of screen (for exposure handling)
*/
void BTXService::redraw_screen_rect(int x1, int y1, int x2, int y2)
{
int x, y;
for(y=y1; y<=y2; y++)
for(x=x1; x<=x2; x++) redrawc(x+1, y+1);
}
/*
* DRC's in the range start-stop with step have been (re)defined.
* This routine checks whether this character is currently visible and so
* needs to be redisplayed.
*/
void BTXService::update_DRCS_display(int start, int stop, int step)
{
int x, y, c;
for(y=0; y<24; y++)
for(x=0; x<40; x++)
if(screen[y][x].set==DRCS)
for(c=start; c<stop; c+=step)
if(screen[y][x].chr==c) redrawc(x+1, y+1);
}
/*
* initialize screen memory and clear display
*/
void BTXService::clearscreen()
{
int x, y;
t.clut = 0;
t.par_attr = 0;
t.par_fg = WHITE;
t.par_bg = TRANSPARENT;
t.scroll_area = 0;
t.scroll_impl = 1;
t.cursorx = t.cursory = 1;
for(y=0; y<24; y++)
for(x=0; x<40; x++) {
screen[y][x].chr = ' ';
screen[y][x].set = PRIM;
screen[y][x].attr = 0;
screen[y][x].real = 0;
screen[y][x].mark = 0;
screen[y][x].fg = WHITE;
screen[y][x].bg = TRANSPARENT;
}
AppDisplay->xclearscreen();
if(t.cursor_on) AppDisplay->xcursor(0, 0);
}
void BTXService::scroll(int up)
{
int y, x, savereal[40];
if(up) {
/* save real attributes of first row */
for(x=0; x<40; x++) savereal[x] = screen[t.scroll_upper-1][x].real;
/* scroll screen memory up */
for(y=t.scroll_upper-1; y<t.scroll_lower-1; y++) {
for(x=0; x<40; x++) screen[y][x] = screen[y+1][x];
}
}
else {
/* scroll screen memory down */
for(y=t.scroll_lower-1; y>t.scroll_upper-1; y--) {
for(x=0; x<40; x++) screen[y][x] = screen[y-1][x];
}
}
/* clear row */
for(x=0; x<40; x++) {
screen[y][x].chr = ' ';
screen[y][x].set = PRIM;
screen[y][x].attr = 0;
screen[y][x].real = 0;
screen[y][x].mark = 0;
screen[y][x].fg = WHITE;
screen[y][x].bg = TRANSPARENT;
}
/* fast scroll the area */
for(y=t.scroll_upper; y<=t.scroll_lower; y++)
for(x=1; x<=40; x++) redrawc(x, y);
/* redraw cursor */
if(t.cursor_on && t.cursory>=t.scroll_upper && t.cursory<=t.scroll_lower)
AppDisplay->xcursor(t.cursorx-1, t.cursory-1);
}
void BTXService::do_Telesoftware(void)
{
int c,i,j,len,total,size,temp;
UBYTE *data,*final;
c = layer2getc();
if(reachedEOF)
return;
switch(c)
{
case 0x27: // D-Set mode, A7.4, p5
for(i = 0 ; i < 4 ; i++)
layer2getc();
c = layer2getc();
if(reachedEOF)
return;
telemode = MODE_Unknown;
if(c == 0x42)
telemode = MODE_3in4;
if(c == 0x41)
telemode = MODE_8Bit;
telesequence = 0x41;
LOG(("d-set mode, mode = %ld\n",telemode));
break;
case 0x33: // D-End group, A7.4, p6
LOG(("d-end group\n"));
if(telefile)
{
fclose(telefile);
telefile = NULL;
}
telemode = MODE_Unknown;
teledownload = FALSE;
telename[0] = 0;
break;
default: // D-Data, A7.4, p3
telesequence = c;
LOG(("sequence code 0x%02lx\n",c));
if(telemode != MODE_3in4) // Hier ist nur 3in4 zugelassen
break;
total = 0;
for(;;)
{
c = layer2getc();
if(reachedEOF)
return;
else
{
if(c == US)
{
layer2ungetc(c);
break;
}
else
telebuffer[total++] = (UBYTE)c;
}
}
len = decode_3in4(telebuffer,telebuffer,total);
data = telebuffer;
while(len > 0)
{
switch(*data)
{
case 0x23: // T-Associate, A7.4, p7
len--;
data++;
LOG(("t-associate\n"));
teledownload = TRUE;
len--;
size = *data++;
len -= size;
data += size;
break;
case 0x63: // T-Filespec, A7.4, p9
len--;
data++;
LOG(("t-filespec\n"));
len--;
size = *data++;
final = data + size;
len -= size;
data++;
size--;
while(size > 0)
{
c = *data++;
size--;
switch(c)
{
case 0x65: // Filename
total = *data++;
size--;
for(j = 0 ; j < total ; j++)
{
telename[j] = (char)*data++;
size--;
}
telename[j] = 0;
LOG(("filename |%s|\n",telename));
break;
case 0x7F: // Date/time
total = *data++;
size--;
for(j = 0 ; j < total ; j++)
{
teledate[j] = (char)*data++;
size--;
}
teledate[j] = 0;
LOG(("date |%s|\n",teledate));
break;
case 0x67: // File length
total = *data++;
size--;
temp = 0;
for(j = 0 ; j < total ; j++)
{
temp = (temp * 256) + (*data++);
size--;
}
telesize = temp;
LOG(("size %ld\n",temp));
break;
default: // Was auch immer...
total = *data++;
size--;
data += total;
size -= total;
break;
}
}
data = final;
break;
case 0x43: // T-Write-Start, A7.4, p10
len--;
data++;
LOG(("t-write-start\n"));
len--;
size = *data++;
len -= size;
data += size;
if(telefile)
{
fclose(telefile);
telefile = NULL;
}
if(!telefile && teledownload)
{
if(telename[0])
telefile = fopen((const char *)telename,"wb");
else
telefile = fopen((const char *)"telesoftware","wb");
}
if(len)
{
LOG(("\t%ld bytes in this block\n",len));
if(telefile)
{
if(fwrite(data,len,1,telefile) != 1)
return;
}
len = 0;
}
break;
case 0x45: // T-Write, A7.4, p11
len--;
data++;
LOG(("t-write\n"));
len--;
size = *data++;
len -= size;
data += size;
if(len)
{
LOG(("\t%ld bytes in this block\n",len));
if(telefile)
{
if(fwrite(data,len,1,telefile) != 1)
return;
}
len = 0;
}
break;
case 0x47: // T-Write-End, A7.4, p11
len--;
data++;
LOG(("t-write-end\n"));
len--;
size = *data++;
len -= size;
data += size;
if(len)
{
LOG(("\t%ld bytes in this block\n",len));
if(telefile)
{
if(fwrite(data,len,1,telefile) != 1)
return;
}
len = 0;
}
if(telefile)
{
fclose(telefile);
telefile = NULL;
}
break;
default:
LOG(("unknown sequence 0x%02lx\n",c));
len--;
data++;
len--;
size = *data++;
len -= size;
data += size;
break;
}
}
break;
}
}
void BTXService::write(const UBYTE *what,int len)
{
App->AppChannel->PutString((CONST STRPTR)what,len);
}
int BTXService::decode_3in4(const UBYTE *data,UBYTE *out,int total)
{
UBYTE buf[4];
int len,eaten,done = 0;
while(total > 0)
{
if(total == 2)
{
buf[0] = (UBYTE)(((data[0] & 0x30) << 2) | (data[1] & 0x3f));
len = 1;
eaten = 2;
}
else
{
if(total == 3)
{
buf[0] = (UBYTE)(((data[0] & 0x30) << 2) | (data[1] & 0x3f));
buf[1] = (UBYTE)(((data[0] & 0x0c) << 4) | (data[2] & 0x3f));
len = 2;
eaten = 3;
}
else
{
if(total >= 4)
{
buf[0] = (UBYTE)(((data[0] & 0x30) << 2) | (data[1] & 0x3f));
buf[1] = (UBYTE)(((data[0] & 0x0c) << 4) | (data[2] & 0x3f));
buf[2] = (UBYTE)(((data[0] & 0x03) << 6) | (data[3] & 0x3f));
len = 3;
eaten = 4;
}
else
break;
}
}
memcpy(out,buf,len);
total -= eaten;
data += eaten;
out += len;
done += len;
}
return(done);
}